﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Services;
using System.Web.SessionState;

using PickGold.Base.Proxies;

using HsjCommon = PickGold.Common;

namespace PickGold.Base.Remoting
{
	/// <summary>
	/// 
	/// </summary>
	//[DataContract]
	//[Serializable]
	[ComVisible(true)]
	[ClassInterface(ClassInterfaceType.AutoDispatch)]
	class MethodInvokerReturnMessage : IMethodReturnMessage, IMethodMessage, IMessage
	{
		private CMethodReturnMessage _Storage;

		public MethodInvokerReturnMessage(CMethodReturnMessage mrm)
		{
			this._Storage = mrm;
		}

		public MethodInvokerReturnMessage(Exception exception, IMethodCallMessage mcm)
		{
			this._Storage = new CMethodReturnMessage();
			this.Storage.Exception = exception;
			if (mcm == null)
				return;

			this.Storage.Uri = mcm.Uri;
			this.Storage.MethodName = mcm.MethodName;
			this.Storage.MethodSignature = mcm.MethodSignature;
			this.Storage.TypeName = mcm.TypeName;
			if (mcm.HasVarArgs)
				this.Storage.Args = mcm.Args;
			this.Storage.MethodBase = mcm.MethodBase;
			this.Storage.LogicalCallContext = mcm.LogicalCallContext;
			this.Storage.Properties = new Hashtable();
		}

		public MethodInvokerReturnMessage(object returnValue, object[] outArgs, LogicalCallContext logicalCallContext, IMethodCallMessage mcm)
		{
			this._Storage = new CMethodReturnMessage();
			this.Storage.ReturnValue = returnValue;
			this.Storage.OutArgs = outArgs;
			this.Storage.LogicalCallContext = logicalCallContext;
			if (mcm == null)
				return;

			this.Storage.Uri = mcm.Uri;
			this.Storage.MethodName = mcm.MethodName;
			this.Storage.MethodSignature = mcm.MethodSignature;
			this.Storage.TypeName = mcm.TypeName;
			this.Storage.Args = mcm.Args;
			this.MethodBase = mcm.MethodBase;
			if (logicalCallContext == null)
				this.Storage.LogicalCallContext = mcm.LogicalCallContext;
			this.Storage.Properties = new Hashtable();
		}

		public MethodInvokerReturnMessage(IMethodReturnMessage mrm, IMethodCallMessage mcm)
		{
			var mir = mrm as MethodInvokerReturnMessage;
			if (mir != null)
			{
				this._Storage = mir.Storage;
				return;
			}

			this._Storage = new CMethodReturnMessage();
			this.Storage.Properties = new Hashtable();
			if (mcm == null)
			{
				if (mrm.Properties != null && mrm.Properties.Count > 0)
				{
					foreach (var key in mrm.Properties.Keys)
						this.Storage.Properties[key] = mrm.Properties[key];
				}
			}
			else
			{
				if (mcm.Properties != null && mcm.Properties.Count > 0)
				{
					foreach (var key in mcm.Properties.Keys)
						this.Storage.Properties[key] = mcm.Properties[key];
				}
			}
			try
			{
				this.Storage.OutArgs = mrm.OutArgs;
				if (this.Storage.OutArgs != null && this.Storage.OutArgs.Length == 0)
				{
					this.Storage.OutArgs = null;
				}
				else
				{
					this.Storage.OutArgNames = new string[this.OutArgCount];
					for (var i = 0; i < mrm.OutArgCount; i++)
						this.Storage.OutArgNames[i] = mrm.GetOutArgName(i);
				}
			}
			catch(Exception x)
			{
				HsjCommon.LastError = x;
			}
			try
			{
				this.Storage.Args = mrm.Args;
				if (this.Storage.Args != null && this.Storage.Args.Length == 0)
				{
					this.Storage.Args = null;
				}
				else
				{
					this.Storage.ArgNames = new string[this.ArgCount];
					for (var i = 0; i < mrm.ArgCount; i++)
						this.Storage.ArgNames[i] = mrm.GetArgName(i);
				}
			}
			catch (Exception x)
			{
				HsjCommon.LastError = x;
			}
			this.Storage.Exception = mrm.Exception;
			this.Storage.ReturnValue = mrm.ReturnValue;
			if (mcm == null)
			{
				this.Storage.LogicalCallContext = mrm.LogicalCallContext;
			}
			else
			{
				this.Storage.LogicalCallContext = mcm.LogicalCallContext;
			}
			this.Storage.MethodBase = mrm.MethodBase;
			this.Storage.MethodName = mrm.MethodName;
			this.Storage.MethodSignature = mrm.MethodSignature;
			this.Storage.TypeName = mrm.TypeName;
			this.Storage.Uri = mrm.Uri;
		}

		public CMethodReturnMessage Storage
		{
			get
			{
				return this._Storage;
			}
		}

		#region IMethodReturnMessage 成员

		public Exception Exception
		{
			set
			{
				this.Storage.Exception = value;
			}
			get
			{
				return this.Storage.Exception;
			}
		}

		public object GetOutArg(int argNum)
		{
			return this.Storage.OutArgs[argNum];
		}

		public string GetOutArgName(int index)
		{
			return this.Storage.OutArgNames[index];
		}

		public int OutArgCount
		{
			get
			{
				if (this.Storage.OutArgs == null)
					return 0;

				return this.Storage.OutArgs.Length;
			}
		}

		public object[] OutArgs
		{
			set
			{
				this.Storage.OutArgs = value;
			}
			get
			{
				return this.Storage.OutArgs;
			}
		}

		public object ReturnValue
		{
			set
			{
				this.Storage.ReturnValue = value;
			}
			get
			{
				return this.Storage.ReturnValue;
			}
		}

		#endregion

		#region IMethodMessage 成员

		public int ArgCount
		{
			get
			{
				if (this.Storage.Args == null)
					return 0;

				return this.Storage.Args.Length;
			}
		}

		public object[] Args
		{
			set
			{
				this.Storage.Args = value;
			}
			get
			{
				return this.Storage.Args;
			}
		}

		public object GetArg(int argNum)
		{
			return this.Storage.Args[argNum];
		}

		public string GetArgName(int index)
		{
			return this.Storage.ArgNames[index];
		}

		public bool HasVarArgs
		{
			get
			{
				if (this.Storage.Args == null || this.Storage.Args.Length == 0)
					return false;

				return true;
			}
		}

		public LogicalCallContext LogicalCallContext
		{
			set
			{
				this.Storage.LogicalCallContext = value;
			}
			get
			{
				return this.Storage.LogicalCallContext;
			}
		}

		public MethodBase MethodBase
		{
			set
			{
				this.Storage.MethodBase = value;
			}
			get
			{
				return this.Storage.MethodBase;
			}
		}

		public string MethodName
		{
			set
			{
				this.Storage.MethodName = value;
			}
			get
			{
				return this.Storage.MethodName;
			}
		}

		public object MethodSignature
		{
			set
			{
				this.Storage.MethodSignature = value;
			}
			get
			{
				return this.Storage.MethodSignature;
			}
		}

		public string TypeName
		{
			set
			{
				this.Storage.TypeName = value;
			}
			get
			{
				return this.Storage.TypeName;
			}
		}

		public string Uri
		{
			set
			{
				this.Storage.Uri = value;
			}
			get
			{
				return this.Storage.Uri;
			}
		}

		#endregion

		#region IMessage 成员

		public IDictionary Properties
		{
			set
			{
				this.Storage.Properties = value;
			}
			get
			{
				return this.Storage.Properties;
			}
		}

		#endregion

		public void Serialize(Stream output)
		{
			this._Storage.Exception = this.Exception;
			this._Storage.ReturnValue = this.ReturnValue;
			this._Storage.OutArgs = this.OutArgs;
			this._Storage.MethodBase = this.MethodBase;
			this._Storage.MethodName = this.MethodName;
			this._Storage.MethodSignature = this.MethodSignature;
			this._Storage.TypeName = this.TypeName;
			this._Storage.ProcessPropertiesProxy(true);
			this._Storage.Serialize(output);//序列化结果。
		}
	}

	[DataContract]
	[Serializable]
	[ComVisible(true)]
	sealed class CMethodReturnMessage : CMessage
	{
		public override void ProcessPropertiesProxy(bool onSerializing)
		{
			base.ProcessPropertiesProxy(onSerializing);
			if (this.OutArgs == null || this.OutArgs.Length == 0)
				return;

			if (onSerializing)//如果正在序列化。
				this.OutProxyArgs = CMessage.ProcessPropertiesProxy(this.OutArgs, null);

			if (this.OutProxyArgs == null || this.OutProxyArgs.Length == 0)//反序列化，如果不存在真实代理
				return;

			CMessage.ProcessPropertiesProxy(this.OutArgs, this.OutProxyArgs);
		}

		public Exception Exception;

		public object ReturnValue;

		public object[] OutArgs;

		public string[] OutArgNames;

		private object[] OutProxyArgs;
	}
}
